﻿using EnvDTE;
using EnvDTE80;

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using Thread=System.Threading.Thread;

namespace VSTools
{
	public class SolutionExplorer
	{
		private DTE2 _vs;
        private int depth = 0;
		private string _findTarget;
		private List<ProjectItem> _solutionItems;
		private string _currentFile;
		//private List<string> _solutionItemNames = new List<string>();
		private Thread _checkForSolutionItems;

		private static class ViewKinds
		{
			//vsViewKindAny,
			public const string vsViewKindCode = "{7651A702-06E5-11D1-8EBD-00A0C90F26EA}";
			//vsViewKindDebugging,
			//vsViewKindDesigner,
			//vsViewKindPrimary,
			//vsViewKindTextView
		}

		private static class ProjectItemKinds
		{
			public const string Project = "{66A26722-8FB5-11D2-AA7E-00C04F688DDE}";
		}

		private enum SolutionItemActions
		{
			BuildList,
			Collapse,
			Open
		}

		public SolutionExplorer(DTE2 VisualStudioIDE)
		{
			_solutionItems = new List<ProjectItem>();
			_vs = VisualStudioIDE;
			System.Diagnostics.Debug.WriteLine("SolutionExplorer instantiated");
			//_solutionOpenedHandler = new _dispSolutionEvents_OpenedEventHandler(SolutionEvents_Opened);
			//_vs.Events.SolutionEvents.Opened += _solutionOpenedHandler;
			//_vs.Events.SolutionItemsEvents.ItemAdded += new _dispProjectItemsEvents_ItemAddedEventHandler(SolutionItemsEvents_ItemAdded);
			//_vs.Events.SolutionItemsEvents.ItemRemoved += new _dispProjectItemsEvents_ItemRemovedEventHandler(SolutionItemsEvents_ItemRemoved);
		}

		public void SolutionOpened()
		{
			//_checkForSolutionItems = new Thread(CheckForSolutionItems);
			//_checkForSolutionItems.Start();
			//_solutionItems.Clear();
			IterateProjects(_vs.Solution.Projects);
			//_solutionItems.Sort(new ProjectItemComparer());
			depth = 99;
		}

		private void IterateProjects(Projects Projects)
		{
			foreach (Project proj in Projects)
			{
				IterateProjectItems(proj.ProjectItems);
			}
		}

		private void IterateProjectItems(ProjectItems Items)
		{
			if (Items == null)
				return;

			foreach (ProjectItem item in Items)
			{
				//System.Diagnostics.Debug.WriteLine(String.Format("Item added: {0}. Children: {1}", item.Name, (item.ProjectItems == null ? 0: item.ProjectItems.Count)));

				if (item.Object is Project) // Opening projects isn't supported by us yet
				{
					IterateProjectItems(((Project)item.Object).ProjectItems);
				}
				else
				{
					if (!Regex.IsMatch(item.Name, @"\.(gif|bmp|png|jpE?g|tiff|ico)$", RegexOptions.IgnoreCase) && item.Kind != EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
						_solutionItems.Add(item);
					System.Diagnostics.Debug.WriteLine("Solution items count: " +  _solutionItems.Count);
					IterateProjectItems(item.ProjectItems);
				}
			}
		}

		private void CheckForSolutionItems()
		{
			//Thread.Sleep(3000);

			//while (Root.UIHierarchyItems.Count == 0)
			//	Thread.Sleep(1000);

			System.Diagnostics.Debug.WriteLine("Count: " + Root.UIHierarchyItems.Count);
			IterateSolutionExplorerItems(SolutionItemActions.BuildList);
			
			//_solutionItemNames.Sort();
		}

		private void SelectionEvents_OnChange()
		{
			throw new NotImplementedException();
		}

		public void CollapseProjects()
		{
			IterateSolutionExplorerItems(SolutionItemActions.Collapse);
		}

		public void FindFile(string FileName)
		{
			if (String.IsNullOrEmpty(FileName))
				return;

			_currentFile = FileName;
			ProjectItem pi = _solutionItems.Find(ProjectItemFinder);
			
			Open(pi);
			if(pi.Document != null)
				pi.Document.Activate();
			//foreach (ProjectItem item in _solutionItems)
			//{
			//	if (item.Name.StartsWith(FileName, System.StringComparison.CurrentCultureIgnoreCase))
			//	{
			//		Open(item);
			//		return;
			//	}
			//}
			//_findTarget = FileName;
			//IterateSolutionItems(SolutionItemActions.Open);
		}

		private void IterateSolutionExplorerItems(SolutionItemActions Action)
		{
			if (Root == null)
				return;
			DoIterateSolutionExplorerItems(Root, Action);
		}

		private void DoIterateSolutionExplorerItems(UIHierarchyItem Item, SolutionItemActions Action)
		{

			//Item.UIHierarchyItems.Expanded = true;
			//Item.UIHierarchyItems.Expanded = true;

			System.Diagnostics.Debug.WriteLine(String.Format("{0}, children: {1} / collection: {2}", Item.Name, Item.UIHierarchyItems.Count, Item.Collection.Count));

			switch (Action)
			{
				case SolutionItemActions.Collapse:

					Collapse(Item);
					break;

				case SolutionItemActions.Open:

					//if (Open(Item))
					//	return;
					//break;

				//case SolutionItemActions.BuildList:

				//	AddSolutionItem(Item);
				//	break;

				default:

					throw new Exception("Unsupported action requested in solution items iteration: " + Action);
			}

			//for (int i = 0; i < Item.UIHierarchyItems.Count; i++)
			foreach (UIHierarchyItem subItem in Item.UIHierarchyItems)
			{
				System.Diagnostics.Debug.WriteLine(String.Format("Items: {0} / {1}", Item.Name, subItem.Name));
				DoIterateSolutionExplorerItems(subItem, Action);
			}

			//foreach (UIHierarchyItem subItem in Item.Collection)// For folders (i think)
			//{
			//	System.Diagnostics.Debug.WriteLine(String.Format("Collection: {0} / {1}", Item.Name, subItem.Name));
				//DoIterateSolutionItems(item, Action);
			//}
		}

		public void CloseAll()
		{
			_vs.Documents.CloseAll(vsSaveChanges.vsSaveChangesPrompt);
			_vs.DTE.Documents.CloseAll(vsSaveChanges.vsSaveChangesPrompt);
			for (int i = 0; i < _vs.Windows.Count; i++)
			{
				if (_vs.Windows.Item(i + 1).ObjectKind == Constants.vsWindowKindObjectBrowser || _vs.Windows.Item(i + 1).ObjectKind == EnvDTE80.WindowKinds.vsWindowKindKindStartPage)
					_vs.Windows.Item(i + 1).Close(vsSaveChanges.vsSaveChangesPrompt);
			}
		}

		private bool Open(ProjectItem Item)
		{
			//Item.Select(vsUISelectionType.vsUISelectionTypeSelect);
			//_vs.ToolWindows.SolutionExplorer.DoDefaultAction();
			//System.Diagnostics.Debug.WriteLine(pi.Kind);
			//if(Item.Kind != Constants.vsprojectitemk)
			Item.Open(Constants.vsViewKindCode);

			return true;
		}

		private void Collapse(UIHierarchyItem Item)
		{
			Item.UIHierarchyItems.Expanded = false;

			if (Item.UIHierarchyItems.Expanded)
			{
				System.Diagnostics.Debug.WriteLine("Collapasing: " + Item.Name);
				Item.Select(vsUISelectionType.vsUISelectionTypeSelect);
				_vs.ToolWindows.SolutionExplorer.DoDefaultAction();
			}
		}

		private void AddSolutionItem(UIHierarchyItem Item)
		{
			if (Item.Object is ProjectItem)
			{
				ProjectItem pi = (ProjectItem)Item.Object;
				//System.Diagnostics.Debug.WriteLine(Item.Name + "Item Kind: " + pi.Kind);
			}
			else if (Item.Object is Project)
			{
				//System.Diagnostics.Debug.WriteLine("Project: " + Item.Name);
			}
			else
				return;
			//GetHierarchyItemType(Item.Object);
			//System.Diagnostics.Debug.WriteLine(String.Format("({0:000}) {1}:{2}", _solutionItems.Count, item.Kind, Item.Name));
			//_solutionItemNames.Add(Item.Name);
			//_solutionItems.Add(Item);
		}

		private void SolutionItemsEvents_ItemRemoved(ProjectItem ProjectItem)
		{
			throw new System.NotImplementedException();
		}

		private void SolutionItemsEvents_ItemAdded(ProjectItem ProjectItem)
		{
			//_solutionItems.Add(ProjectItem);
		}

		private UIHierarchyItem Root
		{
			get
			{
				if (_vs.ToolWindows.SolutionExplorer.UIHierarchyItems.Count == 0)
					return null;
				return _vs.ToolWindows.SolutionExplorer.UIHierarchyItems.Item(1);
			}
		}

		private void GetHierarchyItemType(object ItemObject)
		{
			Type[] types = Assembly.LoadWithPartialName("EnvDTE").GetExportedTypes();

			foreach (Type t in types)
			{
				if (t.IsInstanceOfType(ItemObject))
				{
					//System.Diagnostics.Debug.WriteLine(t);
					break;
				}
			}
		}

		public string[] FileList
		{
			get
			{
				return new List<string>(_solutionItems.ConvertAll<string>(Converter)).ToArray();
			}
		}

		private string Converter(ProjectItem In)
		{
			return In.Name;
		}

		private bool ProjectItemFinder(ProjectItem PI)
		{
			return PI.Name == _currentFile;
		}
	}

	public class UIHierarchyItemComparer: IComparer<UIHierarchyItem>
	{
		public int Compare(UIHierarchyItem A, UIHierarchyItem B)
		{
			try
			{
				if (!(A.Name is String))
					return -1;
			}
			catch (Exception ex)
			{
				return -1;
			}

			try
			{
				if (!(B.Name is String))
					return -1;
			}
			catch (Exception ex)
			{
				return 01;
			}
			return String.Compare(A.Name, B.Name);
		}
	}

	public class ProjectItemComparer : IComparer<ProjectItem>
	{
		public int Compare(ProjectItem A, ProjectItem B)
		{
			try
			{
				if (!(A.Name is String))
					return -1;
			}
			catch (Exception ex)
			{
				return -1;
			}

			try
			{
				if (!(B.Name is String))
					return -1;
			}
			catch (Exception ex)
			{
				return -1;
			}
			return String.Compare(A.Name, B.Name);
		}
	}
}